<?php
/**
 * Created by PhpStorm.
 * User: wanglin
 * Date: 2018/9/13
 * Time: 14:36
 */

namespace App\Console\Commands\ThirdOrder;


use App\Models\Order;
use common\enum\CommonEnum;
use common\utils\RedisKeys;
use App\Services\ThirdAPI\GameApiService;
use App\Services\ThirdAPI\LEBOAPIService;
use App\Services\UserService;
use Illuminate\Support\Facades\Redis;

class LEBOOrderProcessor extends BaseOrderProcessor
{

    protected $signature = self::PREFIX . 'lebo';
    protected $description = 'LEBO注单拉取';

    public $leboService;
    public $redis;
    // 拉取注单开始时间
    public $updateRedisKey = RedisKeys::LEBO_GET_ORDERS_TIME;
    // 自动重拉更新锁 redis key
    public $lockRedisKey = RedisKeys::LEBO_LOCK_AUTOFIX;

    // 当前最新的拉取注单更新时间
    public $latestUpdateKey;


    // 拉取下注记录开始时间
    public $getRecordNextTimeKey = RedisKeys::LEBO_BET_RECORD_TIME;

    // 当下次投注记录拉取时间
    public $latestRecordUpdateKey;

    //自动重拉更新锁
    public $recordBetResultLock = RedisKeys::LEBO_BET_RECORD_LOCK_AUTOFIX;


    public function init($argv = null)
    {
        parent::init();
        $this->redis = Redis::connection();
        $this->leboService = new LEBOAPIService();
        // 5.第三方 partner id，名字，对应第三方表id
        $this->partnerName = "LEBO";
        $info = GameApiService::getApiPartnerInfoByName($this->partnerName);
        $this->partnerID = $info['id'];
        $this->orderType = self::ORDER_TYPE_LIVE;
        $this->reportOrderType = self::GAME_TYPE_LIVE;
        $this->userInfos = [];
    }


    /**
     * 获取注单的投注记录
     */
    public function getBetList()
    {
        $startTime = OrderStrategy::getUpdateKey($this->lockRedisKey, $this->updateRedisKey);//获取注单的拉取时间
        // 检测是否需要重新拉取注单，每次重拉 1 小时前的注单
        $nextTime = OrderStrategy::getUpdateKey($this->recordBetResultLock, $this->getRecordNextTimeKey);
        if (strtotime($nextTime) - strtotime($startTime) > 0) {//不能让下注记录拉取时间大于注单拉取时间
            $nextTime = date("Y-m-d H:i:s", strtotime($startTime) - 20 * 60);
        }
        $result = $this->leboService->getBetList($nextTime);
        if (!empty($result['next_time'])) {//拉取的返回时间
            $this->latestRecordUpdateKey = $result['next_time'];
        } else {
            $this->latestRecordUpdateKey = $nextTime;
        }
        $data = $result['data'];
        if (!empty($data)) {
            $resultDetailArray = [];
            foreach ($data as $v) {
                if (!isset($v['user_name']) || !isset($v['order_number'])) {
                    continue;
                }
                if (!isset($resultDetailArray[$v['user_name'] . $v['order_number']])) {
                    $resultDetailArray[$v['user_name'] . $v['order_number']] = [];
                    $resultDetailArray[$v['user_name'] . $v['order_number']]['order_number'] = $v['order_number'];
                    $resultDetailArray[$v['user_name'] . $v['order_number']]['user_name'] = $v['user_name'];
                    $resultDetailArray[$v['user_name'] . $v['order_number']]['data'] = [];
                }
                $resultDetailArray[$v['user_name'] . $v['order_number']]['data'][] = ['id' => $v['record_id'], 'user_name' => $v['user_name'], 'bet_money' => $v['bet_money'], 'bet_type' => $v['bet_type'], 'record_time' => $v['record_time'], 'order_number' => $v['order_number']];
            }
            $records = array_values($resultDetailArray);
            if (!empty($records)) {
                $this->handleData($records);
            }
        }
        $this->redis->set($this->getRecordNextTimeKey, $this->latestRecordUpdateKey);
    }






    /**
     * 向第三方API抓取数据
     */
    function catchData()
    {
        // 检测是否需要重新拉取注单，每次重拉 1 小时前的注单
        $startTime = OrderStrategy::getUpdateKey($this->lockRedisKey, $this->updateRedisKey);
        $result = $this->leboService->getLEBOOrderLists($startTime);
        if (!empty($result['next_time'])) {//拉取的返回时间
            $this->latestUpdateKey = $result['next_time'];
        } else {
            $this->latestUpdateKey = $startTime;
        }
        return $result['data'];
    }


    function updateFlag($updateKey)
    {
        $this->redis->set($this->updateRedisKey, $this->latestUpdateKey);
        sleep(1);
        $this->getBetList();//此处要拉取注单下注记录
    }

    /**
     * 处理数据
     */
    function load($data)
    {
        $this->betTime = $data['bet_time'];
        $this->settleTime = $data['settle_time'];
        $this->reportTime = $data['report_time'];
        $this->betMoney = $data['bet_money'];
        $this->prizeMoney = $data['prize_money'];
        $this->winLossMoney = $data['winloss_money'];
        $this->apiUserName = $data['api_username'];
        $this->contributeMoney = $data['contribute_money'];
        $this->bonusMoney = $data['bonus_money'];
        $this->validMoney = $data['valid_money'];
        $this->commonStatus = $data['common_status'];
        $this->updateKey = $data['update_key'];
        $this->apiStatus = $data['api_status'];
        $this->gameCode = $data['game_code'];
        $this->gameName = $data['game_name'];
        $this->betContent = $data['bet_content'];
        $this->originData = $data['origin_data'];
        $this->orderNumber = $data["order_number"];
    }

    /**
     * 处理数据，每个子类需要根据第三方的单条数据内容来获取有用的信息
     */
    function initFromData($data)
    {
        // TODO: Implement initFromData() method.
    }

    /**
     * 修复数据内容，每个子类需要实现怎么修复数据内容
     */
    function fixData($date)
    {
        // TODO: Implement fixData() method.
    }

    /**
     * 去除重复注单，UG，SB，BG 一次拉取会有重复注单出现，但是状态不变
     */
    function removeRepeat($data)
    {
        $tmpRecord = [];
        $finalData = [];
        foreach ($data as $key => $value) {
            $orderNumber = $value['order_number'];//唯一订单号
            if (isset($tmpRecord[$orderNumber])) {
                $index = $tmpRecord[$orderNumber];
                if ($finalData[$index]['api_status'] == 0) {//如果有相同的则，已结算的需要替换掉未结算的
                    $finalData[$index] = $value;
                }
                continue;
            }
            $finalData[] = $value;
            $tmpRecord[$orderNumber] = count($finalData) - 1;
        }
        return $finalData;
    }


    public function handleData(array $data): void
    {
        foreach ($data as $value){
           $hallId=$this->getHallIDFromName($value['user_name']);
            $orderModel = Order::where(['order_number' => $value['order_number'], 'partner_id' => $this->partnerID,'hall_id'=>$hallId,'partner_account'=>$value['user_name']])->first();
            if(empty($orderModel)){
                continue;
            }
            $ordBetContent=$orderModel->extends;
            $ordBetContent=empty($ordBetContent)?[]:json_decode($ordBetContent,true);
            $newBetContent=array_merge($ordBetContent,$value['data']);//合并后的数组
            $newBetData=$this->repData($newBetContent);//去重
            $money=array_sum(array_column($newBetData,'bet_money'));
             if($orderModel->bet_amount ==$money*CommonEnum::MONEY_RATE){//此时已拉取到所有的
                 $orderModel->bet_content=$this->betContents($newBetData);
             }
            $orderModel->extends=json_encode($newBetData,320);
            if(!$orderModel->save()){
                continue;
            }
        }
    }

    /**二维数组去重
     * @param array $data
     * @return array
     */
    public function repData(array $data):array {
             $result=[];
              foreach ($data as  $value){
                    if(isset($result[$value['id']])){//此id为下注记录唯一id
                        continue;
                    }
                  $result[$value['id']] =$value;
              }
              return array_values($result);
    }

    /**
     * 构造结果内容
     * @param array $data
     * @return string
     */
   public function betContents(array $data):string {
       $result=[];
       foreach ($data as $value){
           $result[]=$value['bet_type'].":".$value['bet_money'];
       }
       return implode(",",$result);
   }

    /**
     * 反复拉取不用更新bet_content
     */
    public function saveOrUpdate()
    {
        $this->hallID = $this->getHallIDFromName($this->apiUserName);
        //判断第三方订单是否存在，需要新增一个表，和model
        $orderModel = Order::where(['order_number' => $this->orderNumber, 'partner_id' => $this->partnerID])->first();
        if ($orderModel) {
            $orderModel->bet_amount = $this->betMoney;
            $orderModel->validbet = $this->validMoney;
            $orderModel->prize = $this->prizeMoney;
            $orderModel->profit = $this->winLossMoney;
            $orderModel->status = $this->commonStatus;
            $orderModel->partner_status = (string)$this->apiStatus;
            $orderModel->game_code = (string)$this->gameCode;
            $orderModel->game_name = $this->gameName;
            $orderModel->game_type = $this->orderType;
//            $orderModel->bet_content = $this->betContent;//更新时不更新这个内容
            $orderModel->last_version_key = $this->updateKey;
            $orderModel->bet_time = $this->betTime;
            $orderModel->report_time = $this->reportTime;
            $orderModel->reckon_time = $this->settleTime;
            $orderModel->source = $this->originData;
            $orderModel->contribute_amount = $this->contributeMoney ?? 0;
            $orderModel->origin = $this->platform ?? CommonEnum::DEVICE_PC;
            $orderModel->bonus_amount = $this->bonusMoney ?? 0;
            $orderModel->sign = md5($this->userID . $this->userName . $this->partnerID . (int)$this->betMoney . (int)$this->validMoney .
                (int)$this->prizeMoney . (int)$this->winLossMoney . $this->orderNumber .
                (int)$this->contributeMoney . (int)$this->bonusMoney);
            $ret = $orderModel->save();
            $this->info("----- Update Data success: {$this->orderNumber}");
        } else {
            $orderModel = new Order();
            $orderModel->user_id = $this->userID;
            $orderModel->hall_id = $this->hallID;
            $orderModel->username = $this->userName;
            $orderModel->partner_account = $this->apiUserName;
            $orderModel->partner_id = $this->partnerID;
            $orderModel->partner_name = $this->partnerName;
            $orderModel->game_code = (string)$this->gameCode;
            $orderModel->game_name = $this->gameName;
            $orderModel->game_type = $this->orderType;
            $orderModel->order_number = $this->orderNumber;
            $orderModel->bet_amount = (int)$this->betMoney;
            $orderModel->validbet = (int)$this->validMoney;
            $orderModel->profit = (int)$this->winLossMoney;
            $orderModel->prize = (int)$this->prizeMoney;
            $orderModel->contribute_amount = (int)$this->contributeMoney;
            $orderModel->bonus_amount = (int)$this->bonusMoney;
            $orderModel->status = $this->commonStatus;
            $orderModel->partner_status = (string)$this->apiStatus;
            $orderModel->bet_time = $this->betTime;
            $orderModel->reckon_time = $this->settleTime;
            $orderModel->report_time = $this->reportTime;
            $orderModel->last_version_key = $this->updateKey;
            $orderModel->bet_content = $this->betContent;
            $orderModel->source = $this->originData;
            $orderModel->origin = $this->platform ?? CommonEnum::DEVICE_PC;
            $orderModel->sign = md5($this->userID . $this->userName . $this->partnerID . (int)$this->betMoney . (int)$this->validMoney .
                (int)$this->prizeMoney . (int)$this->winLossMoney . $this->orderNumber .
                (int)$this->contributeMoney . (int)$this->bonusMoney);
            $ret = $orderModel->save();
            $this->info("===== Save Data success: {$this->orderNumber}");
        }
        if (!$ret) {
            $msg = "{$this->partnerName} 保存注单失败，需要重新拉取, updateKey: {$this->updateKey}, time: {$this->betTime}, error:";
            $this->error($msg);
            return error_exit(SysCode::INTERNAL_SERVER_ERROR, $msg);
        }
    }

}